<!--
*- coding = utf-8 -*-
#@Time : 2023-06-29 23:59
#@Author : 管茂良
#@File : virtualList.vue
#@web  : www.php-china.com
#@Software: WebStorm
-->
<template>
    <div>
        <div class="listContainer" :style="{height:props.containerHeight}" @scroll="handleScroll">
            <div class="listContainerPhantom" :style="{ height: listHeight + 'px' }"></div>
            <div class="listContainerList" :style="{ transform: computedTransform }">
                <template v-for="(item,index) in computedVisibleData">
                    <slot :data="item"></slot>
                </template>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
    import {computed, nextTick, onMounted, ref, watch} from "vue";

    let startNum = ref(0)
    let endNum = ref(0)

    let startOffset = ref(0);//偏移量
    let listHeight = ref(0);//列表总高度
    let listItemHeight = ref(0);//每项高度

    interface propsInterface{
      data?:any              //列表数据
      containerHeight?:string   //容器高度
    }
    let props = withDefaults(defineProps<propsInterface>(),{
      //所有数据
      data:[],
      containerHeight:"",
    })

    const computedTransform = computed(()=>{
        return `translate3d(0,${startOffset.value}px,0)`;
    })
    //可看得见的数据
    const computedVisibleData = computed(()=>{
        return props.data.slice(startNum.value,Math.min(endNum.value,props.data.length))
    })


    const handleScroll = ()=>{
        let listContainer = document.querySelector(".listContainer");//列表容器
        let listContainerHeight = listContainer.offsetHeight

        //可显示的数量
        let showNum = Math.ceil(listContainerHeight / listItemHeight.value)

        //滚动高度
        let contentScrollTop = Math.floor(listContainer.scrollTop);

        let curNum = Math.ceil(contentScrollTop / listItemHeight.value);
        startNum.value = curNum
        endNum.value = showNum + startNum.value

      //滚动高度减去空隙
      startOffset.value = contentScrollTop - (contentScrollTop%showNum)

    }

    const handleInit = ()=>{
        let listContainer = document.querySelector(".listContainer");//列表容器
        let listItem = document.querySelector(".listItem");//每一列

        let listContainerHeight = listContainer?.offsetHeight
        listItemHeight.value = listItem?.offsetHeight??1

        //列表总高度
        listHeight.value = props.data.length*listItemHeight.value

        startNum.value = 0
        let showNum = Math.ceil(listContainerHeight / listItemHeight.value)
        endNum.value = startNum.value + showNum
    }
    //监听列表高度，有变化，重新初始化
    watch(()=>listItemHeight.value,(value)=>{
      handleInit()
    },{immediate:true,deep:true})

    onMounted(()=>{
        handleInit()
        nextTick(()=>{
          listItemHeight.value = document.querySelector(".listItem").offsetHeight
        })
    })
</script>

<style scoped lang="less">
    .listContainer{
        height:400px;
        overflow: auto;
        position: relative;
        -webkit-overflow-scrolling: touch;
        .listContainerPhantom{
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            z-index: -1;
        }
        .listContainerList{
            left: 0;
            right: 0;
            top: 0;
            position: absolute;
            text-align: center;
        }

    }
</style>
